﻿// 0825train03.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include <string>
#include <sstream>
#include <vector>
#include <algorithm>
#include <limits>
#include <queue>
#include <unordered_map>
#include <unordered_set>

using namespace std;

/*
 在斗地主扑克牌游戏中，扑克牌由小到大的顺序为：
 3,4,5,6,7,8,9,10,J,Q,K,A,2。 

玩家可以出的扑克牌阵型有：单张、对子顺子、飞机、炸弹等。
其中顺子的出牌规则为：由至少5张由小到大连续递增的扑克牌组成，且不能包含2。 
例如：{3,4,5,6,7}、{3,4,5,6,7,8,9,10,J,Q,K,A}都是有效的顺子；
而{J,Q,K,A,2}、{2,3,4,5,6}、{3,4,5,6}、{3,4,5,6,8}等都不是顺子。

给定一个包含13张牌的数组，如果有满足出牌规则的顺子，请输出顺子。 
如果存在多个顺子，请每行输出一个顺子，且需要按顺子的第一张牌的大小（必须从小到大）依次输出。
如果没有满足出牌规则的顺子，请输出No。

输入描述
13张任意顺序的扑克牌，每张扑克牌数字用空格隔开，
每张扑克牌的数字都是合法的，并且不包括大小王。
比如： 2 9 J 2 3 4 K A 7 9 A 5 6 
不需要考虑输入为异常字符的情况

输出描述
组成的顺子，每张扑克牌数字用空格隔开。比如
3 4 5 6 7

输入
2 9 J 10 3 4 K A 7 Q A 5 6
输出
3 4 5 6 7
9 10 J Q K A
 */

class Solution01
{
public:
    string translateCards(string oh_str)
    {
        //J11 Q12 K13 A14 2 15
        if (oh_str=="J")
        {
            return "11";
        }
        if (oh_str == "11")
        {
            return "J";
        }

        if (oh_str=="Q")
        {
            return"12";
        }
        if (oh_str=="12")
        {
            return "Q";
        }

        if (oh_str == "K")
        {
            return"13";
        }
        if (oh_str == "13")
        {
            return "K";
        }

        if (oh_str == "A")
        {
            return"14";
        }
        if (oh_str == "14")
        {
            return "A";
        }

        if (oh_str == "2")
        {
            return"15";
        }
        if (oh_str == "15")
        {
            return "2";
        }
        return oh_str;
    }

    void updateResult()
    {
        result_.push_back(track_vec_);
        //更新num_vec
        for (auto&num:track_vec_)
        {
            num_vec[num] -= 1;
        }
        track_vec_.clear();
    }

	Solution01(vector<string>&cards_vec)
    {
        //转成数字3-14 2不能算进去
        num_vec.resize(15);
        for (auto&oh_str:cards_vec)
        {
            int index = stoi(translateCards(oh_str));
            if (index == 15)continue;
            num_vec[index] += 1;
        }

        //5张由小到大连续递增的扑克牌组成，且不能包含2
        //从3开始扫，扫到为0的情况就break
        //两对34567怎么处理
        int index = 3;
        while (index<num_vec.size())
        {
            if (num_vec[index] == 0)
            {
                index++;
                continue;
            }

            track_vec_.push_back(index);
            for (int right=index+1; right<num_vec.size();right++)
            {
                //没有牌，退出
                if (num_vec[right] == 0) break;
                track_vec_.push_back(right);
            }
            if (track_vec_.size()>=5)
            {
                updateResult();
            }
            else
            {
                track_vec_.clear();
                index++;
            }

        }

        if (result_.empty())
        {
            cout << "No";
            return;
        }

        for (auto&mini_vec:result_)
        {
	        for (auto&num:mini_vec)
	        {
                cout << translateCards(to_string(num)) << ' ';
	        }
            cout << '\n';
        }
    }
private:
    vector<int>num_vec;
    vector<vector<int>>result_;
    vector<int>track_vec_;
};


class Solution11
{
public:
    string translateCards(string&oh_str)
    {
        //J11 Q12 K13 A14 2 15
        unordered_map<string, string>cards_map =
        { {"J","11"}, {"11","J"},
			{"Q","12"},{"12","Q"},
			{"K","13"},{"13","K"},
			{"A","14"},{"14","A"},
			{"2","15"},{"15","2"}
        };
        if (cards_map.count(oh_str)>0)
        {
            return cards_map.at(oh_str);
        }
        return oh_str;
    }
    void extendResult()
    {
        for (auto&min_vec:result_vec)
        {
            while (min_vec.back()!=14 && num_vec[min_vec.back()+1]>0)
            {
                num_vec[min_vec.back() + 1] -= 1;
                min_vec.push_back(min_vec.back() + 1);
            }
        }
    }

    void coutResult()
    {
        sort(result_vec.begin(), result_vec.end(), [](vector<int>&a, vector<int>&b)
            {
                return a.size() < b.size();
            });

        for (auto&min_vec:result_vec)
        {
	        for (auto&num:min_vec)
	        {
                string card_str = to_string(num);
                cout << translateCards(card_str) << ' ';
	        }
            cout << '\n';
        }

    }

    Solution11(vector<string>&cards_vec)
    {
        //3-14,2不包含
        num_vec.resize(15);
        for (auto&oh_str:cards_vec)
        {
            int index = stoi(translateCards(oh_str));
            if (index == 15)continue;
            num_vec[index] += 1;
        }

        int i = 3;
        while (i < num_vec.size())
        {
            if (num_vec[i] == 0)
            {
                i++;
                continue;
            }

            track_vec.push_back(i);
            for (int right = i + 1; right<num_vec.size() && right <= i + 4; right++)
            {
                if (num_vec[right] == 0)
                {
                    break;
                }
                track_vec.push_back(right);
            }
            if (track_vec.size()==5)
            {
                for (auto&track_i:track_vec)
                {
                    num_vec[track_i] -= 1;
                }

                result_vec.push_back(track_vec);
                track_vec.clear();
            }
            else
            {
                track_vec.clear();
                i++;
            }

        }

        if (result_vec.empty())
        {
            cout << "No";
            return;
        }

        extendResult();
        coutResult();

    }
private:
    vector<int>num_vec;
    vector<int>track_vec;
    vector<vector<int>>result_vec;
};

int main()
{
    vector<string>cards_vec;
    string input = "2 9 9 9 3 4 K A 10 Q A 5 6";
    //string input;
    //getline(cin, input);
    stringstream oh_sstream(input);
    string token;
    while (oh_sstream>>token)
    {
        cards_vec.push_back(token);
    }
    Solution11 solu(cards_vec);
}

// 运行程序: Ctrl + F5 或调试 >“开始执行(不调试)”菜单
// 调试程序: F5 或调试 >“开始调试”菜单

// 入门使用技巧: 
//   1. 使用解决方案资源管理器窗口添加/管理文件
//   2. 使用团队资源管理器窗口连接到源代码管理
//   3. 使用输出窗口查看生成输出和其他消息
//   4. 使用错误列表窗口查看错误
//   5. 转到“项目”>“添加新项”以创建新的代码文件，或转到“项目”>“添加现有项”以将现有代码文件添加到项目
//   6. 将来，若要再次打开此项目，请转到“文件”>“打开”>“项目”并选择 .sln 文件
